﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using YKXiangQi.Common;
using YKXiangQi.EventHandlers;

namespace YKXiangQi.Controls
{
    public class CommandTextBox: TextBox
    {
        private List<string> BuiltinCommands { get; set; }

        private int _currentLine = 0;

        public int MaxLengthPerLine { get; set; }

        public CommandTextBox()
        {
            MaxLengthPerLine = 50;
            this.AcceptsReturn = true;
            this.PreviewTextInput += OnPreviewTextInput;
            this.PreviewKeyDown += OnPreviewKeyDown;
            CommandManager.AddPreviewExecutedHandler(this, OnPreviewCommand);
            BuiltinCommands = new List<string> {"clear"};
        }

        protected void OnPreviewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                    case Key.Return:
                    {
                        var lineIndex = this.GetLineIndexFromCharacterIndex(this.CaretIndex);
                        if (lineIndex == _currentLine)
                        {
                            var text = this.GetLineText(lineIndex).Trim();
                            if (!string.IsNullOrEmpty(text))
                            {
                                var inputArray = text.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
                                var command = inputArray[0];
                                if(BuiltinCommands.Contains(command))
                                {
                                    bool isIgnoreAction = ProcessCommand(command);
                                    if (isIgnoreAction)
                                    {
                                        e.Handled = true;
                                        return;
                                    }
                                }
                                else
                                {
                                    var param = new InputCommandEventArgs() {Text = text};
                                    if (InputCommand != null && InputCommand.CanExecute(param))
                                    {
                                        InputCommand.Execute(param);
                                        Dispatcher.BeginInvoke(new Action(() =>
                                                                              {
                                                                                  this.Text += param.Output +
                                                                                               Environment.NewLine;
                                                                                  this.CaretIndex = this.Text.Length;
                                                                                  _currentLine++;
                                                                              }));
                                    }
                                }
                                _currentLine++;
                            }
                            else
                                e.Handled = true;
                        }
                        else
                            e.Handled = true;

                        break;
                    }
                    case Key.Back:
                    {
                        var lineIndex = this.GetLineIndexFromCharacterIndex(this.CaretIndex);
                        if (lineIndex < _currentLine)
                        {
                            e.Handled = true;
                            return;
                        }
                        
                        if (lineIndex == _currentLine)
                        {
                            var lineLength = this.GetLineLength(lineIndex);
                            if (lineLength == 0)
                                e.Handled = true;
                        }

                        break;
                    }
                    case Key.Delete:
                    {
                        var lineIndex = this.GetLineIndexFromCharacterIndex(this.CaretIndex);
                        if (lineIndex < _currentLine)
                            e.Handled = true;
                        break;
                    }
            }
           
        }

        protected void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            var lineIndex = this.GetLineIndexFromCharacterIndex(this.CaretIndex);
            if (lineIndex < _currentLine)
            {
                e.Handled = true;
                return;
            }

            var lineLength = this.GetLineLength(lineIndex);
            if (lineLength > MaxLengthPerLine)
                e.Handled = true;
        }

        protected void OnPreviewCommand(object sender, ExecutedRoutedEventArgs e)
        {
            if (e.Command == ApplicationCommands.Cut || e.Command == ApplicationCommands.Copy
                || e.Command == ApplicationCommands.Paste)
            {
                e.Handled = true;
            }
        }

        public void ClearScreen()
        {
            this.Text = string.Empty;
            _currentLine = 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns>return true to ignore the action</returns>
        private bool ProcessCommand(string command)
        {
            switch (command)
            {
                case Constant.Commands.Clear:
                    {
                        ClearScreen();
                        return true;
                    }
            }

            return false;
        }

        public static readonly DependencyProperty InputCommandProperty =
            DependencyProperty.Register("InputCommand", typeof (ICommand), typeof (CommandTextBox), new PropertyMetadata(default(ICommand)));

        public ICommand InputCommand
        {
            get { return (ICommand) GetValue(InputCommandProperty); }
            set { SetValue(InputCommandProperty, value); }
        }
    }
}
